package com.ujoku.controller.admin;

import com.labillusion.core.crypto.HMAC;
import com.labillusion.core.platform.crypto.MD5;
import com.labillusion.core.platform.web.filter.RequestWrapper;
import com.labillusion.core.platform.web.rest.RESTController;
import com.labillusion.core.util.Convert;
import com.labillusion.core.util.EncodingUtils;
import com.labillusion.core.util.StringUtils;
import com.labillusion.core.util.UUIDUtils;
import com.ujoku.domain.Client;
import com.ujoku.domain.admin.User;
import com.ujoku.interceptor.admin.oa.OAConstant;
import com.ujoku.service.ClientService;
import com.ujoku.service.admin.UserService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

@Controller
public class AdminIndexController extends RESTController{
    private static org.slf4j.Logger logger = LoggerFactory.getLogger(AdminIndexController.class);

    @Autowired
    private UserService userService;

    @Autowired
    private ClientService clientService;

    @Value("#{configProperties['settings.prov.area']}")
    private String areaWebsite;


    @RequestMapping(value="/uj-admin", method = RequestMethod.GET)
    public String adminIndex(ModelMap model) throws Exception {
        model.put("areaWebsite" ,areaWebsite);

        return "admin/index";
    }

    @RequestMapping(value="/uj-oa-login", method = RequestMethod.GET)
    public String oaLogin(ModelMap model, HttpServletRequest request) throws Exception {
        int status = authenticateClient((RequestWrapper) request);
        if(status == OAConstant.ERROR){
            return "redirect:/oa-error";
        }else if(status == OAConstant.EXPIRED){
            return "redirect:/oa-expired";
        }
        return "redirect:/uj-oa";
    }

    private int authenticateClient(RequestWrapper request) throws Exception {

        String clientId = request.getParameter(OAConstant.CLIENTID);
        if (!StringUtils.hasText(clientId)) {
            request.getSession().setAttribute("error","找不到clientId");
            return OAConstant.ERROR;
        }

        String signature = request.getParameter(OAConstant.SIGNATURE);
        if (!StringUtils.hasText(signature)) {
            request.getSession().setAttribute("error","找不到签名");
            return OAConstant.ERROR;
        }

        String method = request.getParameter(OAConstant.METHOD);
        if (!StringUtils.hasText(method))
        {
            request.getSession().setAttribute("error","找不到method");
            return OAConstant.ERROR;
        }

        String userName = request.getParameter(OAConstant.USERNAME);
        if (!StringUtils.hasText(userName))
        {
            request.getSession().setAttribute("error","找不到管理员");
            return OAConstant.ERROR;
        }

        String password = request.getParameter(OAConstant.PASSWORD);
        if(userName.equals("oaAdmin") && !StringUtils.hasText(password)){
            request.getSession().setAttribute("error","找不到登录密码");
            return OAConstant.ERROR;
        }

        String timestamp = request.getParameter(OAConstant.TIMESTAMP);
        if (!StringUtils.hasText(timestamp))
        {
            request.getSession().setAttribute("error","找不到访问时间");
            return OAConstant.ERROR;
        }

        String ascription = request.getParameter(OAConstant.ASCRIPTION);
        if (!userName.equals("oaAdmin") && !StringUtils.hasText(ascription))
        {
            request.getSession().setAttribute("error","找不到归属");
            return OAConstant.ERROR;
        }

        HttpSession session = request.getSession();
        if (session == null) {
            request.getSession().setAttribute("error","找不到session");
            return OAConstant.ERROR;
        }

        User user = (User) session.getAttribute("user");
        if (user != null && userName.equals(user.getName())) {
            if(user.getName().equals("oaAdmin") && !password.equals(user.getPassword())){
                request.getSession().setAttribute("error","密码错误");
                return OAConstant.ERROR;
            }
            return OAConstant.SUCCESS;
        }

        Map<String, Object> query = new HashMap<>();
        query.put("ClientId", clientId);
        Client client = (Client) clientService.selectOne(query);
        if (client == null) {
            request.getSession().setAttribute("error","找不到client");
            return OAConstant.ERROR;
        }

        String key = client.getSecretKey();

        if(!isExpired(request)){
            request.getSession().setAttribute("error","访问超时");
            return OAConstant.EXPIRED;
        }

        String message = buildSignedMessage(request);
        String exceptedSignature = EncodingUtils.encryptBASE64(HMAC.encryptHMAC(message.getBytes(Charset.forName("UTF-8")), key));
        //验证签名
        if (!signature.equalsIgnoreCase(exceptedSignature)){
            logger.error("message:" + message + ",signature:" + signature + ",exceptedSignature:" + exceptedSignature);
            request.getSession().setAttribute("error","签名错误");
            return OAConstant.ERROR;
        }


        Map<String,Object> userQuery = new HashMap<>();
        userQuery.put("name",userName);
        user = (User) userService.selectOne(userQuery);

        if(user == null){
            user = new User();
            user.setId(UUIDUtils.random());
            user.setName(userName);
            user.setPassword(MD5.encrypt(user.getId() + "123456"));
            userService.insert(user);
        }else if(user.getName().equals("oaAdmin") && !password.equals(user.getPassword())){
            request.getSession().setAttribute("error","登录密码错误");
            return OAConstant.ERROR;
        }

        session.setAttribute("user", user);
        session.setAttribute("ascription",ascription);

        return OAConstant.SUCCESS;
    }

    private String buildSignedMessage(RequestWrapper request) {
        String clientId = request.getParameter(OAConstant.CLIENTID);
        String timestamp = request.getParameter(OAConstant.TIMESTAMP);
        String method = request.getParameter(OAConstant.METHOD);
        String userName = request.getParameter(OAConstant.USERNAME);
        String ascription = request.getParameter(OAConstant.ASCRIPTION);
        String password = request.getParameter(OAConstant.PASSWORD);

        StringBuilder builder = new StringBuilder(300);
        builder.append("uri=").append(request.getRequestURI());
        builder.append("?userName=").append(userName);
        builder.append("&password=").append(password);
        builder.append("&ascription=").append(ascription);
        builder.append("&clientId=").append(clientId);
        builder.append("&method=").append(method);
        builder.append("&timestamp=").append(timestamp);

        return builder.toString();
    }

    private Boolean isExpired(RequestWrapper request) {
        String timestamp = request.getParameter(OAConstant.TIMESTAMP);

        if (!StringUtils.hasText(timestamp)){
            return false;
        }

        Long clientTimestamp = Convert.toLong(timestamp, null);
        if (clientTimestamp == null) {
            return false;
        }
        Long serverTimeStamp = System.currentTimeMillis();
        if (clientTimestamp + (5 * 60 * 1000) < serverTimeStamp) {
            return false;
        }

        return true;
    }

    @RequestMapping(value="/uj-oa", method = RequestMethod.GET)
    public String memberMngPage(ModelMap model , HttpServletRequest request) throws Exception {

        User user = (User)request.getSession().getAttribute("user");

        String ascription = "";

        if(!user.getName().equals("oaAdmin")) {
            ascription = (String) request.getSession().getAttribute("ascription");
        }

        model.put("ascription", ascription);

        return "admin/oaIndex";
    }


    @RequestMapping(value="/oa-error", method = RequestMethod.GET)
    public String error(ModelMap model , HttpServletRequest request) throws Exception {

        String errorMsg = (String) request.getSession().getAttribute("error");

        model.put("errorMsg",errorMsg);

        return "admin/error";
    }

    @RequestMapping(value="/oa-expired", method = RequestMethod.GET)
    public String expired() throws Exception {

        return "admin/expired";
    }
}